'''
Created on Sept 16, 2013

@author: Patrick Janssen
'''

import sys, os
from string import Template
from core.modules.vistrails_module import Module, ModuleError
import json
from constants import *

''' ---------------------------------------------------------------------------
Houdini
--------------------------------------------------------------------------- '''
class Houdini(Module):
    def compute(self):

        #Check inputs
        if not self.hasInputFromPort("houdini_file"):
            raise ModuleError(self, "Needs houdini_file")
        if not self.hasInputFromPort("parameters_file"):
            raise ModuleError(self, "Needs parameters_file")
        if not self.hasInputFromPort("input_node_path"):
            raise ModuleError(self, "Needs input_node_path")
        if not self.hasInputFromPort("output_node_path"):
            raise ModuleError(self, "Needs output_node_path")
        houdini_file = self.getInputFromPort("houdini_file")
        parameter_file = self.getInputFromPort("parameters_file")
        input_node_path = self.getInputFromPort("input_node_path")
        output_node_path = self.getInputFromPort("output_node_path")

        #Get the paths of the files
        houdini_file_path = os.path.abspath(houdini_file.name)
        parameter_file_path = os.path.abspath(parameter_file.name)

        #Create the temp and putput files
        temp_script_file = self.interpreter.filePool.create_file(suffix=".py")
        geo_output_file = self.interpreter.filePool.create_file(suffix=".json")
        temp_script_file_path = os.path.abspath(temp_script_file.name)
        geo_output_file_path = os.path.abspath(geo_output_file.name)

        #Create hython script
        hython_script_template = """
import hou
import json
try:
    warnings = hou.hipFile.load(r"$HOUDINI_FILE_PATH ")
    if warnings:
        print warnings
except hou.LoadWarning as e:
    raise ModuleError(self, "Error: hou.LoadWarning exception loading hip file: " + e)
except hou.OperationFailed as e:
    raise ModuleError(self, "Error: hou.OperationFailed exception loading hip file: " + e)
except Exception as e:
    raise ModuleError(self, "Error: Exception loading hip file: " + e)
except:
    raise ModuleError(self, "Error: Unrecognised exception loading hip file")
input_node = hou.node("$INPUT_NODE_PATH")
if not input_node:
    raise ModuleError(self, "Error: Houdini node $INPUT_NODE_PATH does not exist.")
output_node = hou.node("$OUTPUT_NODE_PATH")
if not output_node:
    raise ModuleError(self, "Error: Houdini node $OUTPUT_NODE_PATH does not exist.")
with open(r"$PARAMETER_FILE_PATH ") as data_file:    
    data = json.load(data_file)
for key, value in data.iteritems():
    input_node.setParms({str(key):value})
output_node.setParms({"file":r"$GEOMETRY_FILE "})
output_node.cook(force=True)
        """

        t = Template(hython_script_template)
        hython_script = t.substitute(
            HOUDINI_FILE_PATH = houdini_file_path,
            PARAMETER_FILE_PATH = parameter_file_path,
            GEOMETRY_FILE = geo_output_file_path,
            INPUT_NODE_PATH = input_node_path,
            OUTPUT_NODE_PATH = output_node_path)
        f = open(temp_script_file_path, 'w')
        f.write(hython_script)
        f.close()

        #Execute the hython script
        os.system("hython " + temp_script_file_path)

        #Set outputs
        self.setResult("geo_output_file", geo_output_file)

    _input_ports = [
        ("houdini_file",FILE,{"optional":False,"sort_key":1}), 
        ("parameters_file",FILE,{"optional":False,"sort_key":2}), 
        ("input_node_path",STRING,{"optional":False,"sort_key":3}), 
        ("output_node_path",STRING,{"optional":False,"sort_key":4})
    ]
    _output_ports = [
        ("geo_output_file",FILE,{"sort_key":1})
    ]
''' ---------------------------------------------------------------------------
HoudiniMapper
--------------------------------------------------------------------------- '''
class HoudiniMapper(Module):
    def compute(self):

        #Check inputs
        if not self.hasInputFromPort("geo_input_file"):
            raise ModuleError(self, "Needs geo_input")
        geo_input_file = self.getInputFromPort("geo_input_file")

        #Get the paths of the files
        geo_input_file_path = os.path.abspath(geo_input_file.name)

        #Get the json data
        with open(geo_input_file_path) as data_file:    
            data = json.load(data_file)
        def sub_data(data, name):
            return data[data.index(name)+1]
        topology = sub_data(data, "topology")
        pointref = sub_data(topology, "pointref")
        indices = sub_data(pointref, "indices")
        attributes = sub_data(data, "attributes")
        pointattributes = sub_data(attributes, "pointattributes")
        vertexattributes = sub_data(attributes, "vertexattributes")
        primitiveattributes = sub_data(attributes, "primitiveattributes")
        globalattributes = sub_data(attributes, "globalattributes")
        values = sub_data(pointattributes[0][1], "values")
        tuples = sub_data(values, "tuples")
        primitives = sub_data(data, "primitives")

        #Get the points
        points = []
        for tuple in tuples:
            pt = [i for i in tuple[:3]]
            points.append(pt)

        #Get the prim attribures
        prims_attribs = []
        for attrib_set in primitiveattributes:
            attrib_info = attrib_set[0]
            attrib_type = sub_data(attrib_info, "type")
            attrib_name = sub_data(attrib_info, "name")
            attrib_data = attrib_set[1]
            attrib_size = sub_data(attrib_data, "size")
            data_list = []
            if attrib_data[6] == "indices":
                attrib_indices_data = sub_data(attrib_data, "indices")
                attrib_strings = sub_data(attrib_data, "strings")
                attrib_values = sub_data(attrib_indices_data, "arrays")
                attrib_values = attrib_values[0] #there should be only one array
                for i in attrib_values:
                    if i == -1:
                        data_list.append(None)
                    else:
                        data_list.append(attrib_strings[i])
            elif attrib_data[6] == "values":
                attrib_values_data = sub_data(attrib_data, "values")
                if attrib_size == 1:
                    attrib_values = sub_data(attrib_values_data, "arrays")
                    attrib_values = attrib_values[0] #there should be only one array
                else:
                    attrib_values = sub_data(attrib_values_data, "tuples")
                data_list = attrib_values
            else:
                raise ModuleError(self, "Found unexpected value in geo file")
            prims_attribs.append({"name":attrib_name,"type":attrib_type, "size":attrib_size, "values": data_list})

        #Get the primitives (only polygons)
        polys = []
        counter = 0
        for prim_set in primitives:
            prim_set_info = prim_set[0]
            prim_set_data = prim_set[1]
            type = sub_data(prim_set_info, "type")
            if type=="Poly":
                verts = [indices[i] for i in prim_set_data[1]]
                closed = prim_set_data[3]
                poly = {"vertices":verts, "closed":closed, "attributes":{}}
                for prims_attrib in prims_attribs:
                    if prims_attrib["values"][counter]:
                        poly["attributes"][prims_attrib["name"]] = {"type":prims_attrib["type"], "value":prims_attrib["values"][counter]}
                polys.append(poly)
                counter += 1
            elif type=="run":
                runtype = sub_data(prim_set_info, "runtype")
                uniformfields = sub_data(prim_set_info, "uniformfields")
                if runtype=="Poly":
                    for prim in prim_set_data:
                        verts = [indices[i] for i in prim[0]]
                        if len(prim) == 1:
                            closed = uniformfields["closed"]
                        else:
                            closed = prim[1]
                        poly = {"vertices":verts, "closed":closed, "attributes":{}}
                        for prims_attrib in prims_attribs:
                            if prims_attrib["values"][counter]:
                                poly["attributes"][prims_attrib["name"]] = {"type":prims_attrib["type"], "value":prims_attrib["values"][counter]}
                        polys.append(poly)
                        counter += 1
                else:
                    counter += len(prim_set_data)
            else:
                counter += 1

        data = {"points":points, "polys":polys}

        #Create the output file
        json_output_file = self.interpreter.filePool.create_file(suffix=".json")
        json_output_file_path = os.path.abspath(json_output_file.name)
        f = open(json_output_file_path, 'w')
        f.write(json.dumps(data))
        f.close()

        #Set output
        self.setResult("json_output_file", json_output_file)

    _input_ports = [
        ("geo_input_file",FILE,{"optional":False,"sort_key":1})
    ]

    _output_ports = [
        ("json_output_file",FILE,{"sort_key":1})
    ]